其實在前面寫 javascript 設定時,已經將後端 tsserver 設定完畢了,這裡只要加入
(add-hook 'typescript-mode-hook #'setup-tide-mode)
讓預設的 typescript-mode 加入 tide-mode 次模式的支援,就可以跟 javascript 一樣使用相關的功能,諸如
我們直接用一個例子來看 Emacs 對於 Angular 專案相關的功能,先來使用
$ng new hello
開啟一個新的專案,這個簡單的專案不需要 Routing, 只需要 css,因為在 vagrant client 下執行,啟動時加入 $ng serve --host 0.0.0.0
專案簡單起見使用 bootstrap (純 CSS 部分),$npm install bootstrap -S
,在 styles.css 加入
@import "~bootstrap/dist/css/bootstrap.css"
加入後,原先的網頁字體也跟著改變了
使用 $ng generate component posts
來建立一個元件,修改 app.component.html為
<div>
<app-posts></app-posts>
</div>
建立基本 html layout
<div class="container">
<h2 class="my-3 text-center">List of all Posts</h2>
<div class="row">
<div class="col-md-6">
<div class="card mb-4 shadow-sm">
<div class="card-body">
<div class="card-title">title</div>
<div class="card-text mb-4">body</div>
<a href="#" class="btn btn-outline-primary">More...</a>
</div>
</div>
</div>
</div>
</div>
完成後的樣子
Angular 建議資料的來源為 Service,將資料與元件(表現資料) 分離,大部分資料來自於 RESTful API 後端,我們可以先用模擬資料先將元件表現的部分確定,以免由於後端的連結問題來糾纏
export class Post {
id:number;
title: string;
body: string
}
import {Post} from "../models/post";
export const POSTS: Post[] = [
{id: 1, title: "first post", body: "first post content"},
{id: 2, title: "secon post", body: "second post content"},
{id: 3, title: "third post", body: "third post content"},
{id: 4, title: "forth post", body: "forth post content"},
];
import { Component, OnInit } from '@angular/core';
import { POSTS } from '../services/mock-posts';
@Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.css']
})
export class PostsComponent implements OnInit {
posts = POSTS;
constructor() { }
ngOnInit() {
console.log(this.posts);
}
}
<div class="container">
<h2 class="my-3 text-center">List of all Posts</h2>
<div class="row">
<div class="col-md-6" *ngFor="let post of posts">
<div class="card mb-4 shadow-sm">
<div class="card-body">
<div class="card-title">{{post.title}}</div>
<div class="card-text mb-4">{{post.body}}</div>
<a href="#" class="btn btn-outline-primary">More...</a>
</div>
</div>
</div>
</div>
</div>
使用者介面的部分大致完成
真正的 Angular 服務應該是從後端連結資料,非同步來提供資料以供元件表現,我們來建立一個服務
$ng generate service posts
先利用先前的 mock-posts 建立一個 Observable
import {Injectable} from "@angular/core";
import {Post} from "../models/post";
import {POSTS} from "./mock-posts";
import {Observable, of} from "rxjs";
@Injectable({
providedIn: "root",
})
export class PostsService {
constructor() {}
getPost(): Observable<Post[]> {
return of(POSTS);
}
}
import {Component, OnInit} from "@angular/core";
import {PostsService} from "../services/posts.service";
@Component({
selector: "app-posts",
templateUrl: "./posts.component.html",
styleUrls: ["./posts.component.css"],
})
export class PostsComponent implements OnInit {
posts = [];
constructor(private postService: PostsService) {}
ngOnInit() {
this.getPosts();
}
getPosts() {
this.postService.getPost().subscribe(posts => (this.posts = posts));
}
}
需要注入(inject) PostService,然後 subscribe 服務,修改完,網頁不變,表示服務已經成功
Ctrl-c ! l
顯示更多訊息 Ctrl-c ! v
可以看在 typescript-mode 下,flycheck 可以使用 tide 或者 tslint,如果要使用 tslint,需要做設定 import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { PostsComponent } from './posts/posts.component';
import { HttpClient } from 'selenium-webdriver/http';
@NgModule({
declarations: [
AppComponent,
PostsComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
import {Injectable} from "@angular/core";
import {HttpClient} from "@angular/common/http";
import {Post} from "../models/post";
//import {POSTS} from "./mock-posts";
import {Observable, of} from "rxjs";
@Injectable({
providedIn: "root",
})
export class PostsService {
constructor(private http: HttpClient) {}
getPost(): Observable<Post[]> {
//return of(POSTS);
return this.http.get<Post[]>(
"https://jsonplaceholder.typicode.com/posts?userId=1",
);
}
}
注入 HttpClietn 服務,這個也是一個 Observable,完成後
加入一個管線 (pipe),讓 body 只顯示最多 50 個字
<div class="card-text mb-3">{{post.body | slice:0:50 }}...</div>
最後的完成畫面
相關影片:
相關簡報: 簡報
相關程式: Github
Emacs 設定檔: Github 請下載到 ~/.emacs.d 啟動 Emacs 即可自動安裝相關套件
相關資訊: 我的部落格